/**
 * @file port_spi.c
 * @brief
 * @author lijingjie (lijingjie@pthyidh.com)
 * @date 2024-11-07 10:27:40
 *
 * @copyright Copyright (c) 2024 by 深圳市鹏天微智能科技有限公司, All Rights Reserved.
 */

/* ==================== [Includes] ========================================== */

#include "xf_hal_port.h"

#if XF_HAL_SPI_IS_ENABLE

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "pt3220.h"
#include "drvs.h"

#include "xf_utils.h"
#include "xf_init.h"

/* ==================== [Defines] =========================================== */

#define XF_HAL_SPI_DEFAULT_HOSTS                1
#define XF_HAL_SPI_DEFAULT_BIT_ORDER            XF_HAL_SPI_BIT_ORDER_MSB_FIRST
#define XF_HAL_SPI_DEFAULT_MODE                 XF_HAL_SPI_MODE_0
#define XF_HAL_SPI_DEFAULT_DATA_WIDTH           XF_HAL_SPI_DATA_WIDTH_8_BITS
#define XF_HAL_SPI_DEFAULT_TIMEOUT              1000
#define XF_HAL_SPI_DEFAULT_SPEED                1000*500
#define XF_HAL_SPI_DEFAULT_SCLK_NUM             1
#define XF_HAL_SPI_DEFAULT_CS_NUM               2
#define XF_HAL_SPI_DEFAULT_MOSI_NUM             3
#define XF_HAL_SPI_DEFAULT_MISO_NUM             4
#define XF_HAL_SPI_DEFAULT_QUADWP_NUM           XF_HAL_GPIO_NUM_NONE
#define XF_HAL_SPI_DEFAULT_QUADHD_NUM           XF_HAL_GPIO_NUM_NONE
#define XF_HAL_SPI_DEFAULT_PREV_CB_CALLBACK     NULL
#define XF_HAL_SPI_DEFAULT_PREV_CB_USER_DATA    NULL
#define XF_HAL_SPI_DEFAULT_POST_CB_CALLBACK     NULL
#define XF_HAL_SPI_DEFAULT_POST_CB_USER_DATA    NULL

#define TAG   ("PORT_SPI")


/* ==================== [Typedefs] ========================================== */

/* ==================== [Static Prototypes] ================================= */

/* ==================== [Static Variables] ================================== */

/* ==================== [Macros] ============================================ */

/* ==================== [Global Functions] ================================== */

/* ==================== [Static Functions] ================================== */

static xf_err_t port_spi_open(xf_hal_dev_t *dev)
{
    if (dev->id != 0)
    {
        return XF_ERR_INVALID_ARG;
    }
    return XF_OK;
}

static xf_err_t port_spi_ioctl(xf_hal_dev_t *dev, uint32_t cmd, void *config)
{
    xf_hal_spi_config_t *spi_config = (xf_hal_spi_config_t *)config;

    if (cmd == XF_HAL_SPI_CMD_DEFAULT) {
        spi_config->hosts               = XF_HAL_SPI_DEFAULT_HOSTS;
        spi_config->bit_order           = XF_HAL_SPI_DEFAULT_BIT_ORDER;
        spi_config->mode                = XF_HAL_SPI_DEFAULT_MODE;
        spi_config->data_width          = XF_HAL_SPI_DEFAULT_DATA_WIDTH;
        spi_config->timeout_ms          = XF_HAL_SPI_DEFAULT_TIMEOUT;
        spi_config->speed               = XF_HAL_SPI_DEFAULT_SPEED;
        spi_config->gpio.sclk_num       = XF_HAL_SPI_DEFAULT_SCLK_NUM;
        spi_config->gpio.cs_num         = XF_HAL_SPI_DEFAULT_CS_NUM;
        spi_config->gpio.mosi_num       = XF_HAL_SPI_DEFAULT_MOSI_NUM;
        spi_config->gpio.miso_num       = XF_HAL_SPI_DEFAULT_MISO_NUM;
        spi_config->gpio.quadhd_num     = XF_HAL_SPI_DEFAULT_QUADWP_NUM;
        spi_config->gpio.quadwp_num     = XF_HAL_SPI_DEFAULT_QUADHD_NUM;
        spi_config->prev_cb.callback    = XF_HAL_SPI_DEFAULT_PREV_CB_CALLBACK;
        spi_config->prev_cb.user_data   = XF_HAL_SPI_DEFAULT_PREV_CB_USER_DATA;
        spi_config->post_cb.callback    = XF_HAL_SPI_DEFAULT_POST_CB_CALLBACK;
        spi_config->post_cb.user_data   = XF_HAL_SPI_DEFAULT_POST_CB_USER_DATA;
        dev->platform_data              = config;

        return XF_OK;
    }

    if (cmd == XF_HAL_SPI_CMD_ALL) {
        return XF_OK;
    }

    if (cmd & XF_HAL_SPI_CMD_BIT_ORDER) {
        if (spi_config->hosts == XF_HAL_SPI_HOSTS_MASTER) {
            spim_set_bit_order((spi_config->bit_order == XF_HAL_SPI_BIT_ORDER_LSB_FIRST) ? 0 : 1);
        } else {
            XF_LOGI(TAG, "SPI slave mode is not currently supported");
            return XF_ERR_NOT_SUPPORTED;
        }
    }

    if (cmd & XF_HAL_SPI_CMD_GPIO) {
        if (spi_config->hosts == XF_HAL_SPI_HOSTS_MASTER) {
            if (spi_config->gpio.cs_num >= 20) {
                return XF_ERR_INVALID_ARG;
            }
            SPIM_CS_INIT(spi_config->gpio.cs_num);
            spim_init(spi_config->gpio.sclk_num, spi_config->gpio.miso_num, spi_config->gpio.mosi_num);
        } else {
            XF_LOGI(TAG, "SPI slave mode is not currently supported");
            return XF_ERR_NOT_SUPPORTED;
        }
    }

    if (cmd & XF_HAL_SPI_CMD_MODE) {
        if (spi_config->hosts == XF_HAL_SPI_HOSTS_MASTER) {
            spim_set_mode(spi_config->mode);
        } else {
            XF_LOGI(TAG, "SPI slave mode is not currently supported");
            return XF_ERR_NOT_SUPPORTED;
        }
    }

    if (cmd & XF_HAL_SPI_CMD_ENABLE) {
        if (spi_config->hosts == XF_HAL_SPI_HOSTS_MASTER) {
            if (spi_config->enable) {
                // spim conf
                spim_conf(SPIM_CR_DFLT);
                spim_ctrl(true);
                SPIM_CS_L(spi_config->gpio.cs_num);
            } else {
                spim_ctrl(false);
            }
        } else { // 从机模式
            XF_LOGI(TAG, "SPI slave mode is not currently supported");
            return XF_ERR_NOT_SUPPORTED;
        }
    }

    if (cmd & XF_HAL_SPI_CMD_DATA_WIDTH) { //只有8位数据，不支持修改。
        XF_LOGE(TAG, "SPI mode not supported: Unsupported clock rate configuration.");
        return XF_ERR_NOT_SUPPORTED;
    }

    return XF_OK;
}

static int port_spi_read(xf_hal_dev_t *dev, void *buf, size_t count)
{
    xf_hal_spi_config_t *spi_config = (xf_hal_spi_config_t *)dev->platform_data;

    if (spi_config->hosts == XF_HAL_SPI_HOSTS_MASTER) {
        if (spi_config->prev_cb.callback) {
            spi_config->prev_cb.callback(dev->id, spi_config->prev_cb.user_data);
        }
        SPIM_CS_L(spi_config->gpio.cs_num);
        spim_receive(buf, count);
        SPIM_CS_H(spi_config->gpio.cs_num);
        if (spi_config->post_cb.callback) {
            spi_config->post_cb.callback(dev->id, spi_config->post_cb.user_data);
        }
    } else {
        XF_LOGI(TAG, "SPI slave mode is not currently supported");
        return -XF_ERR_NOT_SUPPORTED;
    }
    return count;
}

static int port_spi_write(xf_hal_dev_t *dev, const void *buf, size_t count)
{
    xf_hal_spi_config_t *spi_config = (xf_hal_spi_config_t *)dev->platform_data;

    if (spi_config->hosts == XF_HAL_SPI_HOSTS_MASTER) {
        if (spi_config->prev_cb.callback) {
            spi_config->prev_cb.callback(dev->id, spi_config->prev_cb.user_data);
        }
        SPIM_CS_L(spi_config->gpio.cs_num);
        spim_transimit(buf, count);
        SPIM_CS_H(spi_config->gpio.cs_num);
        if (spi_config->post_cb.callback) {
            spi_config->post_cb.callback(dev->id, spi_config->post_cb.user_data);
        }
    } else {
        XF_LOGI(TAG, "SPI slave mode is not currently supported");
        return -XF_ERR_NOT_SUPPORTED;
    }
    return count;
}

static xf_err_t port_spi_close(xf_hal_dev_t *dev)
{
    return XF_OK;
}

static int xf_hal_spi_reg(void)
{
    xf_driver_ops_t ops = {
        .open = port_spi_open,
        .ioctl = port_spi_ioctl,
        .write = port_spi_write,
        .read = port_spi_read,
        .close = port_spi_close,
    };
    xf_hal_spi_register(&ops);
    return XF_OK;
}

XF_INIT_EXPORT_PREV(xf_hal_spi_reg);

#endif
